﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;


namespace Lynn.Infastructure.Repository.EFCore
{
    [AppIgnore]
    public class EFCoreBaseRepository<T> : IEFCoreBaseRepository<T> where T : class
    {
        EFCoreBaseContext Context { get; set; }
        protected DbSet<T> Db { get; private set; }
        public EFCoreBaseRepository(EFCoreBaseContext context)
        {
            this.Context = context;
            Db = Context.Set<T>();
        }

        public async Task<bool> Instert(T entity)
        {
            await Db.AddAsync(entity);
            return await Commit();
        }

        public async Task<bool> Delete(T entity)
        {
            Db.Remove(entity);
            return await Commit();
        }

        public async Task<bool> Update(T entity)
        {
            Db.Update(entity);
            return await Commit();
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> where)
        {
            var db = Db.Where(where);
            return db.AsQueryable();
        }

        public IQueryable<T> QueryIgnoreLogDelete(Expression<Func<T, bool>> where)
        {
            var db = Db.IgnoreQueryFilters().Where(where);
                    //.Where(post => EF.Property<bool>(post, "IsDel"));
            return db.AsQueryable();

        }


        public T QueryFirst(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includes)
        {
            var db = Db.Where(where);
            foreach (var item in includes)
            {
                db = db.Include(item);
            }
            return db.AsQueryable().FirstOrDefault();
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] includes)
        {
            var db = Db.Where(where);
            foreach (var item in includes)
            {
                db = db.Include(item);
            }
            return db.AsQueryable();
        }
        public async Task<bool> Commit()
        {
            return await Context.SaveChangesAsync() > 0;
        }

        public void InstertByCommit(T entity)
        {
            Db.Add(entity);
        }


        public void DeleteByCommit(T entity)
        {
            //entity.RowVersion++;
            Db.Remove(entity);
        }

        public void UpdateByCommit(T entity)
        {
            //entity.RowVersion++;
            Db.Update(entity);
        }

        public IList<T> GetListPage(int page, int pageSize, out int totalPage, out int totalCount, Expression<Func<T, bool>> where, Expression<Func<T, object>> order, bool orderByasc = true)
        {
            if (page < 1)
            {
                throw new Exception("页码从1开始计算");
            }
            var query = Db.Where(where);
            if (orderByasc)
            {
                query = query.OrderBy(order);
            }
            else
            {
                query = query.OrderByDescending(order);
            }
            totalCount = query.Count();
            totalPage = (int)Math.Ceiling(totalCount / pageSize * 1.0d);
            return query.Skip(pageSize * (page - 1)).Take(pageSize).ToList();
        }

        public async Task<bool> Instert(IEnumerable<T> entities)
        {
            await Db.AddRangeAsync(entities);
            return await Commit();
        }

        public async Task<bool> Delete(IEnumerable<T> entities)
        {
            Db.RemoveRange(entities);
            return await Commit();
        }
        public void DeleteByCommit(IEnumerable<T> entities)
        {
            Db.RemoveRange(entities);
        }

        public async Task<bool> Update(IEnumerable<T> entities)
        {
            Db.UpdateRange(entities);
            return await Commit();
        }

        public async Task<IList<T>> GetList(Expression<Func<T, bool>> where)
        {
            return await Db.Where(where).ToListAsync();
        }

        public async Task<bool> Update(Expression<Func<T, bool>> where, object param)
        {
            var entiteis = await Db.Where(where).ToListAsync();
            foreach (var entity in entiteis)
            {
                var ps = entity.GetType().GetProperties();
                foreach (var item in ps)
                {
                    var t = param.GetType().GetProperty(item.Name);
                    if (t == null)
                    {
                        continue;
                    }
                    var value = t.GetValue(param);
                    item.SetValue(entity, value);
                }
                Db.Update(entity);
            }
            return await Commit();
        }
    }
}
